package bcpay

import (
	"context"
	"errors"
	"fmt"

	"gitee.com/liuxuezhan/ar-platform/admin-api/internal/pay/base"
	"gitee.com/liuxuezhan/ar-platform/admin-api/pkg/emun"
	"gitee.com/liuxuezhan/ar-platform/admin-api/pkg/xerrors/assets"
	"github.com/bytedance/sonic/decoder"
	"github.com/zeromicro/go-zero/core/logc"
)

type Factory struct {
}

type Bcpay struct {
	AppId     string
	SecretKey string
	Url       string
	ReturnUrl string
	NotifyUrl string
}

type BalanceResp struct {
	Currency     string  `json:"currency"`     // 币种
	PayinValue   float64 `json:"payinValue"`   // 代收余额
	PayoutValue  float64 `json:"payoutValue"`  // 代付余额
	DisableValue float64 `json:"disableValue"` // 冻结余额
}

type Resp struct {
	Code  int64  `json:"code"`
	Msg   string `json:"msg"`
	Error string `json:"error"`
	Data  any    `json:"data"`
}

func (p *Factory) CreatePay(config base.Config) base.Payment {
	return &Bcpay{
		Url:       config.Url,
		AppId:     config.AppId,
		SecretKey: config.SecretKey,
		ReturnUrl: config.ReturnUrl,
		NotifyUrl: config.NotifyUrl,
	}
}

// 代付订单创建
func (bc *Bcpay) Withdraw(ctx context.Context, req map[string]any) (base.WithdrawRes, error) {
	// 请求第三方接口
	url := bc.Url + "/payout/order/create"
	params := make(map[string]any)
	params["appId"] = bc.AppId
	params["merOrderNo"] = req["Order"].(map[string]any)["OrderNo"]
	params["currency"] = "BRL"
	params["amount"] = fmt.Sprintf("%.2f", req["Order"].(map[string]any)["RealAmount"])
	params["notifyUrl"] = bc.NotifyUrl
	extra := map[string]any{
		"bankCode":    emun.GetUserPixWalletNameByType(int(req["Order"].(map[string]any)["UserPixWallets"].(map[string]any)["WalletType"].(int32))),
		"accountNo":   req["Order"].(map[string]any)["UserPixWallets"].(map[string]any)["Account"],
		"accountName": req["Order"].(map[string]any)["UserPixWallets"].(map[string]any)["Username"],
		"document":    req["Order"].(map[string]any)["UserPixWallets"].(map[string]any)["Cpf"],
	}
	params["extra"] = extra
	params["sign"] = GenerateSign(params, bc.SecretKey)
	params["extra"] = extra
	result, err := sendRequest(ctx, url, params, "post")
	if err != nil {
		return base.WithdrawRes{}, err
	}
	// 验签
	sign := GenerateSign(result.Data.(map[string]any), bc.SecretKey)
	if sign != result.Data.(map[string]any)["sign"] {
		logc.Error(ctx, sign, result)
		return base.WithdrawRes{}, assets.ErrSignVerifyFailed
	}

	return base.WithdrawRes{
		OrderSn:      req["Order"].(map[string]any)["OrderNo"].(string),
		ThirdOrderSn: result.Data.(map[string]any)["orderNo"].(string),
	}, nil
}

// 余额查询
func (bc *Bcpay) Balance(ctx context.Context) (BalanceResp, error) {
	// 请求第三方接口
	url := bc.Url + "/merchant/balance"
	params := make(map[string]any)
	params["appId"] = bc.AppId
	params["sign"] = GenerateSign(params, bc.SecretKey)
	result, err := sendRequest(ctx, url, params, "get")
	if err != nil {
		return BalanceResp{}, err
	}
	// 验签
	sign := GenerateSign(result.Data.(map[string]any), bc.SecretKey)
	if sign != result.Data.(map[string]any)["sign"] {
		return BalanceResp{}, errors.New("Response data sign error")
	}
	return BalanceResp{
		Currency:     result.Data.(map[string]any)["currency"].(string),
		PayinValue:   result.Data.(map[string]any)["payinValue"].(float64),
		PayoutValue:  result.Data.(map[string]any)["payoutValue"].(float64),
		DisableValue: result.Data.(map[string]any)["disableValue"].(float64),
	}, nil
}

// 发送请求
func sendRequest(ctx context.Context, url string, params map[string]any, method string) (resp Resp, err error) {
	output, err := base.SendJson(ctx, url, params, method)
	if err != nil {
		return resp, err
	}
	dc := decoder.NewDecoder(output)
	dc.UseNumber()
	dc.Decode(&resp)
	if resp.Code != 0 {
		return resp, errors.New(resp.Error)
	}
	return
}
